<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JSON数据扁平化工具</title>
    <style>
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }

        body {
            font-family: 'Arial', sans-serif;
            line-height: 1.6;
            color: #333;
            background-color: #f5f7fa;
            padding: 20px;
        }

        .container {
            max-width: 1200px;
            margin: 0 auto;
            background-color: #fff;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            padding: 20px;
        }

        h1 {
            text-align: center;
            margin-bottom: 20px;
            color: #2c3e50;
        }

        .description {
            text-align: center;
            margin-bottom: 30px;
            color: #7f8c8d;
        }

        .tool-container {
            display: flex;
            flex-wrap: wrap;
            gap: 20px;
        }

        .input-section,
        .output-section {
            flex: 1;
            min-width: 300px;
        }

        .section-title {
            font-size: 18px;
            margin-bottom: 10px;
            color: #2c3e50;
        }

        textarea {
            width: 100%;
            height: 300px;
            padding: 12px;
            border: 1px solid #ddd;
            border-radius: 4px;
            resize: none;
            font-family: monospace;
            font-size: 14px;
        }

        .controls {
            margin: 15px 0;
            display: flex;
            flex-wrap: wrap;
            gap: 10px;
        }

        button {
            padding: 10px 15px;
            background-color: #3498db;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            transition: background-color 0.3s;
        }

        button:hover {
            background-color: #2980b9;
        }

        .example-btn {
            background-color: #2ecc71;
        }

        .example-btn:hover {
            background-color: #27ae60;
        }

        .clear-btn {
            background-color: #e74c3c;
        }

        .clear-btn:hover {
            background-color: #c0392b;
        }

        .stats {
            margin-top: 15px;
            padding: 10px;
            background-color: #f8f9fa;
            border-radius: 4px;
            font-size: 14px;
        }

        .stats p {
            margin: 5px 0;
        }

        .error {
            color: #e74c3c;
            margin-top: 10px;
            font-size: 14px;
        }

        .success {
            color: #2ecc71;
            margin-top: 10px;
            font-size: 14px;
        }

        .examples-container {
            margin-top: 30px;
        }

        .example-title {
            font-size: 16px;
            margin-bottom: 10px;
            color: #2c3e50;
        }

        .example-description {
            margin-bottom: 15px;
            color: #7f8c8d;
            font-size: 14px;
        }

        .example-list {
            display: flex;
            flex-wrap: wrap;
            gap: 10px;
        }
    </style>
</head>

<body>
    <div class="container">
        <h1>JSON数据扁平化工具</h1>
        <p class="description">将复杂嵌套数组转换为扁平结构，适用于API响应处理、数据可视化和批量操作</p>

        <div class="tool-container">
            <div class="input-section">
                <h2 class="section-title">输入JSON数据</h2>
                <textarea id="input-json" placeholder="在此输入嵌套的JSON数组数据..."></textarea>
                <div class="controls">
                    <button id="flatten-btn">扁平化处理</button>
                    <button id="example1-btn" class="example-btn">示例1: 产品目录</button>
                    <button id="example2-btn" class="example-btn">示例2: 组织架构</button>
                    <button id="example3-btn" class="example-btn">示例3: 评论嵌套</button>
                    <button id="clear-btn" class="clear-btn">清空</button>
                </div>
                <div id="input-error" class="error"></div>
            </div>

            <div class="output-section">
                <h2 class="section-title">扁平化结果</h2>
                <textarea id="output-json" readonly placeholder="扁平化后的结果将显示在这里..."></textarea>
                <div class="stats" id="stats-container">
                    <p>原始数据层级: <span id="original-depth">-</span></p>
                    <p>原始数据元素数量: <span id="original-count">-</span></p>
                    <p>扁平化后元素数量: <span id="flattened-count">-</span></p>
                    <p>处理时间: <span id="process-time">-</span> ms</p>
                </div>
                <div id="output-success" class="success"></div>
            </div>
        </div>

        <div class="examples-container">
            <h2 class="example-title">业务应用场景</h2>
            <p class="example-description">扁平化处理在以下业务场景中非常有用:</p>
            <ul>
                <li>处理复杂的API响应数据，将多层级数据转换为易于处理的一维数组</li>
                <li>在数据可视化前对嵌套数据进行预处理</li>
                <li>对多层级数据进行批量操作和过滤</li>
                <li>简化复杂数据结构，提高前端渲染性能</li>
                <li>将树形结构转换为表格形式以便于展示和导出</li>
            </ul>
        </div>
    </div>

    <script>
        // 深度扁平化数组的核心函数
        const deepFlatten = arr =>
            [].concat(...arr.map(v => (Array.isArray(v) ? deepFlatten(v) : v)));

        // 计算数组嵌套深度
        function getArrayDepth(arr) {
            if (!Array.isArray(arr)) return 0;
            let maxDepth = 0;
            for (const item of arr) {
                if (Array.isArray(item)) {
                    const depth = getArrayDepth(item);
                    if (depth > maxDepth) maxDepth = depth;
                }
            }
            return maxDepth + 1;
        }

        // 计算数组中元素总数（包括嵌套数组中的元素）
        function countArrayElements(arr) {
            if (!Array.isArray(arr)) return 0;
            let count = 0;
            for (const item of arr) {
                if (Array.isArray(item)) {
                    count += countArrayElements(item);
                } else {
                    count++;
                }
            }
            return count;
        }

        // 业务示例数据
        const examples = {
            // 示例1: 产品目录 - 多层级产品分类
            productCatalog: [
                {
                    id: 1, name: "电子产品", subcategories: [
                        {
                            id: 11, name: "手机", products: [
                                { id: 111, name: "iPhone 13", price: 6799 },
                                { id: 112, name: "Samsung S21", price: 5999 }
                            ]
                        },
                        {
                            id: 12, name: "电脑", products: [
                                { id: 121, name: "MacBook Pro", price: 12999 },
                                { id: 122, name: "ThinkPad X1", price: 9999 }
                            ]
                        }
                    ]
                },
                {
                    id: 2, name: "家居用品", subcategories: [
                        {
                            id: 21, name: "厨房用具", products: [
                                { id: 211, name: "炒锅", price: 199 },
                                { id: 212, name: "刀具套装", price: 299 }
                            ]
                        }
                    ]
                }
            ],

            // 示例2: 组织架构 - 公司部门和员工的层级结构
            organization: [
                {
                    id: 1, name: "技术部", teams: [
                        {
                            id: 11, name: "前端团队", members: [
                                { id: 111, name: "张三", role: "高级前端工程师" },
                                { id: 112, name: "李四", role: "前端工程师" }
                            ]
                        },
                        {
                            id: 12, name: "后端团队", members: [
                                { id: 121, name: "王五", role: "后端架构师" },
                                { id: 122, name: "赵六", role: "后端工程师" }
                            ]
                        }
                    ]
                },
                {
                    id: 2, name: "产品部", teams: [
                        {
                            id: 21, name: "产品设计", members: [
                                { id: 211, name: "钱七", role: "产品经理" },
                                { id: 212, name: "孙八", role: "UI设计师" }
                            ]
                        }
                    ]
                }
            ],

            // 示例3: 评论嵌套 - 社交媒体或论坛的评论和回复结构
            comments: [
                {
                    id: 1, author: "用户A", content: "这是一个很好的产品", replies: [
                        {
                            id: 11, author: "用户B", content: "我同意你的观点", replies: [
                                { id: 111, author: "用户C", content: "我也这么认为" }
                            ]
                        },
                        { id: 12, author: "用户D", content: "价格有点贵" }
                    ]
                },
                {
                    id: 2, author: "用户E", content: "使用体验一般", replies: [
                        {
                            id: 21, author: "客服", content: "请问有什么具体问题吗？", replies: [
                                { id: 211, author: "用户E", content: "电池续航不太好" }
                            ]
                        }
                    ]
                }
            ]
        };

        // 将对象数组转换为扁平数组的业务处理函数
        function flattenBusinessData(data) {
            if (!Array.isArray(data)) return [];

            // 递归提取嵌套对象中的数组
            function extractArrays(item) {
                if (!item || typeof item !== 'object') return item;

                const arrays = [];

                // 遍历对象的所有属性
                for (const key in item) {
                    const value = item[key];

                    // 如果属性值是数组，将其添加到结果中
                    if (Array.isArray(value)) {
                        arrays.push(value);
                        // 递归处理数组中的每个元素
                        for (const element of value) {
                            const nestedArrays = extractArrays(element);
                            if (nestedArrays.length > 0) {
                                arrays.push(...nestedArrays);
                            }
                        }
                    }
                    // 如果属性值是对象，递归处理
                    else if (value && typeof value === 'object') {
                        const nestedArrays = extractArrays(value);
                        if (nestedArrays.length > 0) {
                            arrays.push(...nestedArrays);
                        }
                    }
                }

                return arrays;
            }

            // 提取所有嵌套数组
            const allArrays = [data];
            for (const item of data) {
                const nestedArrays = extractArrays(item);
                if (nestedArrays.length > 0) {
                    allArrays.push(...nestedArrays);
                }
            }

            // 使用deepFlatten扁平化所有提取的数组
            return deepFlatten(allArrays);
        }

        // DOM元素
        const inputTextarea = document.getElementById('input-json');
        const outputTextarea = document.getElementById('output-json');
        const flattenBtn = document.getElementById('flatten-btn');
        const example1Btn = document.getElementById('example1-btn');
        const example2Btn = document.getElementById('example2-btn');
        const example3Btn = document.getElementById('example3-btn');
        const clearBtn = document.getElementById('clear-btn');
        const inputError = document.getElementById('input-error');
        const outputSuccess = document.getElementById('output-success');
        const originalDepthEl = document.getElementById('original-depth');
        const originalCountEl = document.getElementById('original-count');
        const flattenedCountEl = document.getElementById('flattened-count');
        const processTimeEl = document.getElementById('process-time');

        // 处理扁平化
        function processFlattening() {
            inputError.textContent = '';
            outputSuccess.textContent = '';

            try {
                const inputValue = inputTextarea.value.trim();
                if (!inputValue) {
                    inputError.textContent = '请输入JSON数组数据';
                    return;
                }

                const inputData = JSON.parse(inputValue);
                if (!Array.isArray(inputData)) {
                    inputError.textContent = '输入必须是一个JSON数组';
                    return;
                }

                const startTime = performance.now();
                const flattenedData = flattenBusinessData(inputData);
                const endTime = performance.now();
                const processTime = (endTime - startTime).toFixed(2);

                outputTextarea.value = JSON.stringify(flattenedData, null, 2);

                // 更新统计信息
                originalDepthEl.textContent = getArrayDepth(inputData);
                originalCountEl.textContent = countArrayElements(inputData);
                flattenedCountEl.textContent = flattenedData.length;
                processTimeEl.textContent = processTime;

                outputSuccess.textContent = '扁平化处理成功！';
            } catch (error) {
                inputError.textContent = `解析错误: ${error.message}`;
            }
        }

        // 加载示例数据
        function loadExample(exampleData) {
            inputTextarea.value = JSON.stringify(exampleData, null, 2);
            processFlattening();
        }

        // 事件监听
        flattenBtn.addEventListener('click', processFlattening);
        example1Btn.addEventListener('click', () => loadExample(examples.productCatalog));
        example2Btn.addEventListener('click', () => loadExample(examples.organization));
        example3Btn.addEventListener('click', () => loadExample(examples.comments));
        clearBtn.addEventListener('click', () => {
            inputTextarea.value = '';
            outputTextarea.value = '';
            inputError.textContent = '';
            outputSuccess.textContent = '';
            originalDepthEl.textContent = '-';
            originalCountEl.textContent = '-';
            flattenedCountEl.textContent = '-';
            processTimeEl.textContent = '-';
        });

        // 初始加载示例1
        window.addEventListener('DOMContentLoaded', () => {
            loadExample(examples.productCatalog);
        });
    </script>
</body>

</html>